Skip to content

[CI] Support package discovery in nested directories - WIP#18495

Draft
mrodm wants to merge 30 commits intoelastic:mainfrom
mrodm:allow-multiple-directories
Draft

[CI] Support package discovery in nested directories - WIP#18495
mrodm wants to merge 30 commits intoelastic:mainfrom
mrodm:allow-multiple-directories

Conversation

@mrodm
Copy link
Copy Markdown
Collaborator

@mrodm mrodm commented Apr 17, 2026

Summary

This PR centralises package discovery logic into a new citools.ListPackages function and uses it across packagenames and codeowners, replacing the previously duplicated filepath.WalkDir implementations. As a side effect, both checks now support packages organised in nested directory structures (e.g. packages/category/my_package), not just flat packages/my_package layouts.

Proposed commit

WHAT:

Allow packages to be placed in nested subdirectories under packages/
(e.g. packages/<category>/<name>) instead of being restricted to the flat
packages/<name> layout. Previously, codeowners
discovery logic would silently ignore any package not sitting directly under
packages/, meaning nested packages would bypass ownership validation entirely.

WHY:

As the number of integrations grows, being able to organise packages into
category subdirectories becomes necessary to keep the repository manageable.
The existing tooling hard-coded a single-level walk, blocking this. This change
makes nested directory layouts a supported and validated structure across all
CI tooling, so teams can start grouping packages without breaking checks.

Changes

dev/citools

  • Add ListPackages(dir string) ([]string, error) — walks a directory recursively, returns sorted paths of all valid packages found. A package is considered valid when its manifest.yml contains non-empty format_version, name, type (one of integration, input, content) and version fields.
  • Extend packageManifest struct with FormatVersion, Type and Version fields, and add an IsValid() method, mirroring the logic previously only present in dev/packagenames.
  • Expose readPackageManifest as ReadPackageManifest so it can be reused from other packages.

dev/packagenames

  • Remove manifest.go and its local packageManifest type; replace all usages with citools.ReadPackageManifest.
  • Replace the internal walkPackagePaths function with a call to citools.ListPackages.

dev/codeowners

  • Replace the inline filepath.WalkDir loop in validatePackages with a call to citools.ListPackages, removing the duplicate discovery logic.
  • Update testdata manifests with the required format_version, name, type and version fields.
  • Add a nested_packages testdata fixture with packages at two directory levels (top-level and under a category/ subdirectory, one with data streams).
  • Add five new TestValidatePackages cases covering: explicit per-package owners, missing owner for a nested package, category-level inherited ownership, valid per-stream ownership in a nested package, and missing stream owner in a nested package.

magefile.go

  • Add a ListPackages mage target that prints all package paths under the packages/ directory, one per line.

.buildkite/scripts/common.sh

  • Add should_test_package helper function that encapsulates the pushd/is_pr_affected/popdpattern along with fatal-error handling, replacing near-identical blocks that were duplicated intest_integrations_with_serverless.shandtrigger_integrations_in_parallel.sh`.

.buildkite/scripts/build_packages.sh

  • Replace the find-based flat directory loop with list_all_directories (backed by mage listPackages) so packages in nested subdirectories are discovered correctly.
  • Replace with_go with with_mage (which calls with_go internally) so mage is available when list_all_directories runs.

Backport pipeline

  • Remove PACKAGE_FOLDER_NAME as a required input parameter from pipeline.backport.yml and backport_branch.sh. The package path is now resolved automatically by a new get_package_path function that looks up the package whose manifest.yml name field matches the given PACKAGE_NAME, using mage listPackages to iterate all discovered packages.
  • Update docs/extend/developer-workflow-support-old-package.md to reflect the removed parameter.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

Author's Checklist

How to test this PR locally

Related issues


This PR was drafted with the assistance of Claude (claude-sonnet-4-6).

jsoriano and others added 7 commits April 16, 2026 19:20
- Add ListPackages function to dev/citools/packages.go that walks a
  directory and returns sorted paths of all valid packages found.
- Extend packageManifest struct with FormatVersion, Type and Version
  fields, and add IsValid() method mirroring dev/packagenames logic.
- Refactor dev/packagenames to delegate package discovery to
  citools.ListPackages, removing the now-redundant walkPackagePaths.

Generated with Claude (claude-sonnet-4-6)
- Rename readPackageManifest to ReadPackageManifest so it can be used
  from other packages.
- Remove dev/packagenames/manifest.go and its local packageManifest
  type, replacing all usages with citools.ReadPackageManifest.
- Update all internal callers (kibana.go, logsdb.go, subscription.go,
  packages.go) to use the renamed function.

Generated with Claude (claude-sonnet-4-6)
- Replace the inline WalkDir loop in validatePackages with a call to
  citools.ListPackages, removing duplicated package-discovery logic.
- Update testdata manifests (devexp, package_1) with the required
  format_version, name, type and version fields so they are recognised
  as valid packages by citools.ListPackages/IsValid.

Generated with Claude (claude-sonnet-4-6)
- Add nested_packages testdata with packages at two directory levels:
  one at the top level and two under a category/ subdirectory, one of
  which has data streams.
- Add five new TestValidatePackages cases covering: all packages with
  explicit owners, a missing owner for a nested package, category-level
  ownership inherited by nested packages, valid per-stream ownership in
  a nested package, and missing stream owner in a nested package.

Generated with Claude (claude-sonnet-4-6)
Add a ListPackages target that calls citools.ListPackages to print all
package paths found under the packages directory, one per line.

Generated with Claude (claude-sonnet-4-6)
@mrodm mrodm self-assigned this Apr 17, 2026
Comment thread dev/codeowners/codeowners.go
Comment on lines 831 to 833
list_all_directories() {
find . -maxdepth 1 -mindepth 1 -type d | xargs -I {} basename {} | sort
mage listPackages | grep -E '^packages/(elastic_package_registry|nginx)$'
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical scripts/common.sh:831

list_all_directories() now hardcodes a grep filter that returns only two package names (elastic_package_registry and nginx). Since callers trigger_integrations_in_parallel.sh and test_integrations_with_serverless.sh iterate over this output to drive CI pipelines, all other packages are silently excluded from testing and publishing. If this restriction is intentional, consider documenting why only these two packages should run; otherwise, the filter should be removed to restore full package coverage.

 list_all_directories() {
-    mage listPackages | grep -E '^packages/(elastic_package_registry|nginx)$'
+    mage listPackages
 }
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/common.sh around lines 831-833:

`list_all_directories()` now hardcodes a grep filter that returns only two package names (`elastic_package_registry` and `nginx`). Since callers `trigger_integrations_in_parallel.sh` and `test_integrations_with_serverless.sh` iterate over this output to drive CI pipelines, all other packages are silently excluded from testing and publishing. If this restriction is intentional, consider documenting why only these two packages should run; otherwise, the filter should be removed to restore full package coverage.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be removed before merging the PR. This grep is there to test just a subset of packages instead of the ~400 packages.

mrodm added 3 commits April 17, 2026 13:11
- Add -d "${WORKSPACE}" to the mage call in list_all_directories so it
  always finds magefile.go regardless of the working directory when invoked.
- Remove pushd packages / popd wrappers in trigger_integrations_in_parallel.sh
  and test_integrations_with_serverless.sh since list_all_directories now
  returns full paths (e.g. packages/nginx) relative to the repo root.
- Fix process_package: the parameter rename from package to package_path was
  incomplete — pushd, teardown calls, and log lines still referenced the
  old ${package} variable (now unbound). Use ${package_path} for directory
  operations and ${package_name} (from package_name_manifest) for labels.
- Update test_one_package.sh to derive parent_path and package_name from
  the received package_path instead of assuming a packages/ prefix.
- Consistently rename local variables from package to package_name across
  check_package, build_zip_package, teardown_*_package, run_tests_package,
  and related helpers.

Generated with Claude (claude-sonnet-4-6)
- Export manifestFileName as ManifestFileName in dev/citools/packages.go
  so it can be reused across packages.
- Remove the duplicate manifestFileName constant from dev/packagenames
  and replace its usage with citools.ManifestFileName.
- Replace the hardcoded "manifest.yml" string in dev/codeowners with
  citools.ManifestFileName.

Generated with Claude (claude-sonnet-4-6)
Generated with Claude (claude-sonnet-4-6)
Comment thread .buildkite/scripts/trigger_integrations_in_parallel.sh
Comment thread .buildkite/scripts/common.sh
Comment thread .buildkite/scripts/trigger_integrations_in_parallel.sh
@mrodm mrodm force-pushed the allow-multiple-directories branch from 17332f9 to e2454f2 Compare April 17, 2026 12:00
Comment thread .buildkite/scripts/trigger_integrations_in_parallel.sh
Extract the pushd/is_pr_affected/popd pattern with error handling
into a reusable should_test_package function, to be used from
test_integrations_with_serverless.sh and trigger_integrations_in_parallel.sh.

Generated with the assistance of Claude Sonnet 4.6
@elastic-vault-github-plugin-prod
Copy link
Copy Markdown

elastic-vault-github-plugin-prod bot commented Apr 17, 2026

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

Replace find-based flat directory loop with list_all_directories so that
packages organised in subdirectories are discovered correctly.
Also replace `cat manifest.yml | yq` with direct `yq manifest.yml` calls.

Generated with the assistance of Claude Sonnet 4.6
Comment on lines 159 to +161

buildkite-agent pipeline upload "${PIPELINE_FILE}"
cat "${PIPELINE_FILE}"
# buildkite-agent pipeline upload "${PIPELINE_FILE}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical scripts/build_packages.sh:159

The buildkite-agent pipeline upload command is replaced with cat, so the pipeline that signs and publishes packages is never uploaded to Buildkite. Built packages will remain in artifacts but never reach the package registry.

 cat "${PIPELINE_FILE}"
-# buildkite-agent pipeline upload "${PIPELINE_FILE}"
+buildkite-agent pipeline upload "${PIPELINE_FILE}"
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/build_packages.sh around lines 159-161:

The `buildkite-agent pipeline upload` command is replaced with `cat`, so the pipeline that signs and publishes packages is never uploaded to Buildkite. Built packages will remain in artifacts but never reach the package registry.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a change to allow debugging the script safely. This will be reverted before merging the PR.

@mrodm mrodm force-pushed the allow-multiple-directories branch from c280270 to 71e903e Compare April 17, 2026 14:50
Comment on lines 88 to 91
if skipPublishing ; then
echo "packageStoragePublish: not the main branch or a backport branch, nothing will be published"
exit 0
# exit 0
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium scripts/build_packages.sh:88

When skipPublishing returns true, the script prints "nothing will be published" but continues executing instead of exiting. This causes the script to proceed through expensive build steps (tool installation, package building, artifact copying, pipeline generation) on branches that should skip publishing entirely, wasting resources and potentially causing side effects.

if skipPublishing ; then
    echo "packageStoragePublish: not the main branch or a backport branch, nothing will be published"
-    # exit 0
+    exit 0
 fi
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/build_packages.sh around lines 88-91:

When `skipPublishing` returns true, the script prints "nothing will be published" but continues executing instead of exiting. This causes the script to proceed through expensive build steps (tool installation, package building, artifact copying, pipeline generation) on branches that should skip publishing entirely, wasting resources and potentially causing side effects.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes related to debugging. It will be reverted before merging.

SIGNING_STEP_KEY: "sign-service"
ARTIFACTS_FOLDER: "packageArtifacts"
DRY_RUN: "${DRY_RUN}"
DRY_RUN: "true"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium scripts/build_packages.sh:150

DRY_RUN is hardcoded to "true" on line 150, so the trigger_publish_packages.sh step always runs in dry-run mode regardless of the DRY_RUN environment variable value. Packages will never actually be published when the pipeline intends to run for real. Consider reverting to "${DRY_RUN}" to respect the environment variable.

Suggested change
DRY_RUN: "true"
DRY_RUN: "${DRY_RUN}"
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/build_packages.sh around line 150:

`DRY_RUN` is hardcoded to `"true"` on line 150, so the `trigger_publish_packages.sh` step always runs in dry-run mode regardless of the `DRY_RUN` environment variable value. Packages will never actually be published when the pipeline intends to run for real. Consider reverting to `"${DRY_RUN}"` to respect the environment variable.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes related to debugging. It will be reverted before merging.

Replace with_go with with_mage so that mage is available when
list_all_directories is called. with_mage already calls with_go
internally so Go setup is preserved.

Generated with the assistance of Claude Sonnet 4.6
Comment on lines 87 to 92

if skipPublishing ; then
echo "packageStoragePublish: not the main branch or a backport branch, nothing will be published"
exit 0
# exit 0
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium scripts/build_packages.sh:87

When skipPublishing returns true, the script prints "nothing will be published" but continues executing instead of exiting. It proceeds to build packages, copy artifacts, and generate the signing/publishing pipeline YAML, wasting CI resources on non-main/non-backport branches. If the DRY_RUN or buildkite-agent pipeline upload guards are re-enabled later, packages could be signed and published from arbitrary feature branches.

@@ -88,5 +88,5 @@
 if skipPublishing ; then
     echo "packageStoragePublish: not the main branch or a backport branch, nothing will be published"
-    # exit 0
+    exit 0
 fi
 
 add_bin_path
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/build_packages.sh around lines 87-92:

When `skipPublishing` returns true, the script prints "nothing will be published" but continues executing instead of exiting. It proceeds to build packages, copy artifacts, and generate the signing/publishing pipeline YAML, wasting CI resources on non-main/non-backport branches. If the `DRY_RUN` or `buildkite-agent pipeline upload` guards are re-enabled later, packages could be signed and published from arbitrary feature branches.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes related to debugging. It will be reverted before merging.

Add a termination check for ownerDir == "/" to prevent an infinite loop
when filepath.Dir reaches the filesystem root on non-Windows systems,
where filepath.Dir("/") returns "/" instead of ".".

Generated with the assistance of Claude Sonnet 4.6
Comment thread dev/codeowners/codeowners.go
Comment thread dev/codeowners/codeowners.go
Comment thread .buildkite/scripts/backport_branch.sh
@mrodm mrodm force-pushed the allow-multiple-directories branch from 542d646 to 351491d Compare April 20, 2026 09:58
if [ "${DRY_RUN}" == "true" ]; then
echo "DRY_RUN enabled. Publish packages steps skipped."
exit 0
# exit 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium scripts/build_packages.sh:119

When DRY_RUN is true, the script prints the skip message but does not exit, so execution continues into the signing/publishing pipeline generation. If the commented buildkite-agent pipeline upload is re-enabled, a dry run would incorrectly trigger live signing/publishing. Consider uncommenting exit 0 to ensure dry runs actually skip the pipeline steps.

Suggested change
# exit 0
exit 0
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/build_packages.sh around line 119:

When `DRY_RUN` is `true`, the script prints the skip message but does not exit, so execution continues into the signing/publishing pipeline generation. If the commented `buildkite-agent pipeline upload` is re-enabled, a dry run would incorrectly trigger live signing/publishing. Consider uncommenting `exit 0` to ensure dry runs actually skip the pipeline steps.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change will be removed before merging. It was required to be able to test this script/process

Comment thread .buildkite/scripts/backport_branch.sh
…port script

Remove the PACKAGE_FOLDER_NAME input parameter from the backport pipeline.
Instead, derive the package path automatically from PACKAGE_NAME by introducing
a get_package_path function that iterates all packages via `mage listPackages`
and matches on the `name` field in manifest.yml.

Also refactor removeOtherPackages to accept the package path as an explicit
parameter instead of relying on a global variable.

Generated with the assistance of Claude Sonnet 4.6
@elasticmachine
Copy link
Copy Markdown

💚 Build Succeeded

History

cc @mrodm

@mrodm mrodm force-pushed the allow-multiple-directories branch from 351491d to ac65fe1 Compare April 20, 2026 10:40
Comment thread .buildkite/scripts/backport_branch.sh
Comment thread .buildkite/scripts/backport_branch.sh Outdated
mrodm added 4 commits April 20, 2026 12:52
…Packages

Replace basename-based sed patterns with the full package path so that
nested packages (e.g. packages/category/nginx) are correctly removed from
CODEOWNERS. Use | as sed delimiter to avoid escaping slashes.

Generated with the assistance of Claude Sonnet 4.6
Add || true to the get_package_path command substitution so a non-zero
return does not trigger set -e before the -z check can run the friendly
error annotation.

Generated with the assistance of Claude Sonnet 4.6
Comment thread .buildkite/scripts/backport_branch.sh Outdated
Comment thread .buildkite/scripts/backport_branch.sh
Comment thread .buildkite/scripts/backport_branch.sh
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 20, 2026

Vale Linting Results

Summary: 8 warnings, 5 suggestions found

⚠️ Warnings (8)
File Line Rule Message
packages/nginx/nginx/_dev/build/docs/README.md 65 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/_dev/build/docs/README.md 81 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/_dev/build/docs/README.md 90 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/_dev/build/docs/README.md 111 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/docs/README.md 181 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/docs/README.md 300 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/docs/README.md 326 Elastic.DontUse Don't use 'Please'.
packages/nginx/nginx/docs/README.md 427 Elastic.DontUse Don't use 'Please'.
💡 Suggestions (5)
File Line Rule Message
packages/nginx/nginx/_dev/build/docs/README.md 32 Elastic.WordChoice Consider using 'refer to if it's a document, view if it's a UI element' instead of 'see', unless the term is in the UI.
packages/nginx/nginx/_dev/build/docs/README.md 48 Elastic.WordChoice Consider using 'deactivate, deselect, hide, turn off' instead of 'disable', unless the term is in the UI.
packages/nginx/nginx/docs/README.md 32 Elastic.WordChoice Consider using 'refer to if it's a document, view if it's a UI element' instead of 'see', unless the term is in the UI.
packages/nginx/nginx/docs/README.md 38 Elastic.WordChoice Consider using 'refer to if it's a document, view if it's a UI element' instead of 'see', unless the term is in the UI.
packages/nginx/nginx/docs/README.md 48 Elastic.WordChoice Consider using 'deactivate, deselect, hide, turn off' instead of 'disable', unless the term is in the UI.

The Vale linter checks documentation changes against the Elastic Docs style guide.

To use Vale locally or report issues, refer to Elastic style guide for Vale.

Comment on lines 865 to 867
list_all_directories() {
find . -maxdepth 1 -mindepth 1 -type d | xargs -I {} basename {} | sort
mage -d "${WORKSPACE}" listPackages | grep -E '^packages/(elastic_package_registry|nginx|rapid7_insightvm|sql_input|nginx/nginx|nginx/nginx_otel)$'
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High scripts/common.sh:865

list_all_directories() at line 866 hardcodes a grep -E filter that restricts output to only 6 specific packages, silently skipping all other packages from the build/publish and serverless testing pipelines. This appears to be a development filter accidentally committed in place of the previous find implementation that listed all package directories. Consider reverting to the previous implementation or using a more appropriate mechanism for temporary filtering.

+# list all directories that are packages from the root of the repository
 list_all_directories() {
-    mage -d "${WORKSPACE}" listPackages | grep -E '^packages/(elastic_package_registry|nginx|rapid7_insightvm|sql_input|nginx/nginx|nginx/nginx_otel)$'
+    find . -maxdepth 1 -mindepth 1 -type d | xargs -I {} basename {} | sort
 }
🤖 Copy this AI Prompt to have your agent fix this:
In file .buildkite/scripts/common.sh around lines 865-867:

`list_all_directories()` at line 866 hardcodes a `grep -E` filter that restricts output to only 6 specific packages, silently skipping all other packages from the build/publish and serverless testing pipelines. This appears to be a development filter accidentally committed in place of the previous `find` implementation that listed all package directories. Consider reverting to the previous implementation or using a more appropriate mechanism for temporary filtering.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this filtering of packages is related to run different testing in CI pipelines. It will be removed that grep and keep the mage -d ${WORKSPACE} listPackages command before merging this PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for confirming. Would you like me to remove the grep filter and restore the command to just mage -d "${WORKSPACE}" listPackages, or will you handle this yourself?

Comment thread .github/CODEOWNERS Outdated
@elasticmachine
Copy link
Copy Markdown

💚 Build Succeeded

History

cc @mrodm

@andrewkroh andrewkroh added Integration:nginx Nginx documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. labels Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:nginx Nginx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for an additional level of directories under packages/

4 participants